/**
 * Mock Data Initialization
 * This file provides functions to initialize and use mock data
 */

import { MockDataAdapter } from './MockDataAdapter';
import { DataSource } from '../services';
import { mockModel } from './data/mockModel';

/**
 * Initialize data sources with mock data
 * This function patches the DataSource fetch methods to use mock data
 */
export function initializeMockData(): void {
  const mockAdapter = MockDataAdapter.getInstance();
  
  // Save original fetch method references
  const originalFetch = window.fetch;
  
  // Replace the global fetch function to intercept OData requests
  window.fetch = function mockedFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {
    let url: string;
    if (typeof input === 'string') {
      url = input;
    } else if (input instanceof URL) {
      url = input.toString();
    } else {
      url = input.url;
    }
    
    // Check if this is an OData request
    if (url.includes('/odata/')) {
      // Extract object type and parameters from URL
      const urlParts = url.split('/odata/');
      if (urlParts.length < 2) {
        return originalFetch(input, init);
      }
      
      const pathParts = urlParts[1].split('?');
      let objectType = pathParts[0];
      const queryString = pathParts.length > 1 ? pathParts[1] : '';
      
      // Check if this is a getByKey request
      const keyMatch = objectType.match(/([^(]+)\(([^)]+)\)/);
      let key = null;
      
      if (keyMatch) {
        objectType = keyMatch[1];
        key = parseInt(keyMatch[2], 10);
      }
      
      // Parse query parameters
      const params = new URLSearchParams(queryString);
      const options: any = {};
      
      if (params.has('$filter')) {
        options.filter = params.get('$filter');
      }
      
      if (params.has('$orderby')) {
        const orderby = params.get('$orderby');
        if (orderby) {
          options.sort = orderby.split(',').map(part => {
            const [field, dir] = part.trim().split(' ');
            return { field, dir: (dir || 'asc') as 'asc' | 'desc' };
          });
        }
      }
      
      if (params.has('$skip')) {
        options.skip = parseInt(params.get('$skip') || '0', 10);
      }
      
      if (params.has('$top')) {
        options.take = parseInt(params.get('$top') || '10', 10);
      }
      
      if (params.has('$expand')) {
        options.expand = params.get('$expand')?.split(',');
      }
      
      if (params.has('$select')) {
        options.select = params.get('$select')?.split(',');
      }
      
      // Handle the request based on HTTP method
      let result: Promise<any>;
      const method = init?.method || 'GET';
      
      switch (method) {
        case 'GET':
          if (key !== null) {
            // Get by key
            result = mockAdapter.getObjectByKey(objectType, key, options);
          } else {
            // Get list
            result = mockAdapter.loadData(objectType, options);
          }
          break;
          
        case 'POST':
          // Create
          if (init?.body) {
            const data = JSON.parse(init.body.toString());
            result = mockAdapter.createObject(objectType, data);
          } else {
            return Promise.reject(new Error('No data provided for POST request'));
          }
          break;
          
        case 'PATCH':
          // Update
          if (key !== null && init?.body) {
            const data = JSON.parse(init.body.toString());
            result = mockAdapter.updateObject(objectType, key, data);
          } else {
            return Promise.reject(new Error('No key or data provided for PATCH request'));
          }
          break;
          
        case 'DELETE':
          // Delete
          if (key !== null) {
            result = mockAdapter.deleteObject(objectType, key).then(() => ({}));
          } else {
            return Promise.reject(new Error('No key provided for DELETE request'));
          }
          break;
          
        default:
          return originalFetch(input, init);
      }
      
      // Create a mocked Response object
      return result.then(data => {
        const responseBody = JSON.stringify(data);
        
        return {
          ok: true,
          status: 200,
          statusText: 'OK',
          headers: new Headers({
            'Content-Type': 'application/json'
          }),
          json: () => Promise.resolve(data),
          text: () => Promise.resolve(responseBody),
          clone: function() { return this; }
        } as Response;      });
    } else if (url.includes('/api/model')) {
      // Return the mock model directly
      const data = mockModel;
      const responseBody = JSON.stringify(data);
      
      return Promise.resolve({
        ok: true,
        status: 200,
        statusText: 'OK',
        headers: new Headers({
          'Content-Type': 'application/json'
        }),
        json: () => Promise.resolve(data),
        text: () => Promise.resolve(responseBody),
        clone: function() { return this; }
      } as Response);
    }
    
    // For all other requests, use the original fetch
    return originalFetch(input, init);
  };
  
  console.log('Mock data initialized. All API requests will use mock data.');
}
